/*
 * Licensed to the Apache Software Foudation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * � License �) ; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * � AS IS � BASIS, WITHOUT WARRANTIES OR CONDITION OF ANY
 * KIND, either express or implied. See the License for the
 * specific langage governing permissions and limitations
 * under the License.
 *
 */
package views;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.ThreadMXBean;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.swing.AbstractListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;

import org.apache.directory.mavibot.btree.JMXMavibotInMemoryBtreeMBean;
import org.apache.directory.mavibot.btree.JMXMavibotPersistedBtreeMBean;
import org.jfree.data.time.Millisecond;

import com.sun.management.GarbageCollectorMXBean;
import com.sun.management.OperatingSystemMXBean;

/**
 * 
 * A panel to show the JMX statistics.
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 */
@SuppressWarnings("restriction")
public class MetricPage extends JPanel
{
    
    private static final long serialVersionUID = 1L;
    
    /** The host for the JMX connection. */
    private JTextField textHost;
    
    /** The port for the JMX connectionr. */
    private JTextField textPort;
    
    /** The connection to the MBean server. */
    private MBeanServerConnection mBeanServerConnection;
    
    /** The mbean of a in memory btree. */
    private JMXMavibotInMemoryBtreeMBean inMemoryBtreeMBean;
    
    /** The mbean of a persisted btree. */
    private JMXMavibotPersistedBtreeMBean persistedBtreeMBean;
    
    /** The mbean for Thread. */
    private ThreadMXBean threadMXBean;
    
    /** The mbean for the first Garbage Collector. */
    private GarbageCollectorMXBean gc1MXBean;
    
    /** The mbean for the second Garbage Collector. */
    private GarbageCollectorMXBean gc2MXBean;
    
    /** The mbean for the operating system. */
    private OperatingSystemMXBean osMXBean;
    
    /** The mbean for the memory. */
    private MemoryMXBean memoryMXBean;
    
    /**  */
    private boolean isPersist=false;
    
    /** The JTable for btree metrics. */
    private JTable tableMetric;
    
    /** A table to keep btree metrics. */
    private String[][] dataMetrics;
    
    /** The JTable for jvm metrics. */
    private JTable tableJVM;
    
    /** A table to keep jvm metrics. */
    private String[][] dataJVM;
    
    /** The default delai for the auto refresh. */
    private int delai= 1000;
    
    /** The refresh delay. */
    private JTextField textRefreshDelay;
    
    /** A Thread to manage the refresh. */
    private RefreshThread refreshThread;
    
    /** The chart for cpu usage. */
    private CourbeJMXPanel cpuPanel;
    
    /** The chart for heap memory usage. */
    private CourbeJMXPanel heapMemoryPanel;
    
    /** The chart for non heap memory usage. */
    private CourbeJMXPanel nonHeapMemoryPanel;
    
    /** The chart for hit/miss percentage. */
    private CourbeJMXPanel hitMissPanel;
    
    /** The list of btree name. */
    private JList<String> btreeBeanList;
    
    /** The list of jvm mbean accessible. */
    private JList<String> statisticList;
    
    /** The list of attribute of the selected mbean. */
    private JList<String> methodList;
    
    /** The table of btree mbean complete name. */
    private String[] tabRealName;
    
    /**
     * 
     * Creates a new instance of MetricPage.
     *
     */
    public MetricPage()
    {
        dataMetrics = new String[][] {  {"Name",""},
                                        {"Type",""},
                                        {"Revision",""},
                                        {"PageSize",""},
                                        {"Element count",""},
                                        {"KeySerializer",""},
                                        {"ValueSerializer",""},
                                        {"ReadTimeOut",""},
                                        {"WriteBufferSize",""},
                                        {" "," "},
                                        {"Cache size",""},
                                        {"Cache access count",""},
                                        {"Cache insert count",""},
                                        {"Cache read count",""},
                                        {"Cache hit count",""},
                                        {"Cache miss count",""}};
        
        dataJVM = new String[][] {  {"%cpu",""},
                                    {"HeapMemoryUsage - committed",""},
                                    {"HeapMemoryUsage - used",""},
                                    {"NonHeapMemoryUsage - committed",""},
                                    {"NonHeapMemoryUsage - used",""},
                                    {"",""},
                                    {"",""},
                                    {"Thread count",""}};
        
        setLayout(new BorderLayout(0, 0));
        
        /* Initialize the left panel with connection part and btree name list, mbean list. */
        
        JPanel panelLeft = new JPanel();
        this.add(panelLeft, BorderLayout.WEST);
        panelLeft.setLayout(new BorderLayout(0, 0));
        
        JPanel panelConnection = new JPanel();
        panelLeft.add(panelConnection, BorderLayout.NORTH);
        GridBagLayout gbl_panelConnection = new GridBagLayout();
        gbl_panelConnection.columnWeights = new double[]{0.5, 0.5};
        gbl_panelConnection.rowWeights = new double[]{0.0, 0.0, 0.0};
        panelConnection.setLayout(gbl_panelConnection);
        
        JLabel lblHost = new JLabel("Host : ");
        GridBagConstraints gbc_lblHost = new GridBagConstraints();
        gbc_lblHost.anchor = GridBagConstraints.WEST;
        gbc_lblHost.insets = new Insets(0, 0, 5, 5);
        gbc_lblHost.gridx = 0;
        gbc_lblHost.gridy = 0;
        panelConnection.add(lblHost, gbc_lblHost);
        
        textHost = new JTextField();
        textHost.setColumns(10);
        GridBagConstraints gbc_textHost = new GridBagConstraints();
        gbc_textHost.insets = new Insets(0, 0, 5, 0);
        gbc_textHost.anchor = GridBagConstraints.NORTHWEST;
        gbc_textHost.gridx = 1;
        gbc_textHost.gridy = 0;
        panelConnection.add(textHost, gbc_textHost);
        
        JLabel lblPort = new JLabel("Port :");
        GridBagConstraints gbc_lblPort = new GridBagConstraints();
        gbc_lblPort.anchor = GridBagConstraints.WEST;
        gbc_lblPort.insets = new Insets(0, 0, 5, 5);
        gbc_lblPort.gridx = 0;
        gbc_lblPort.gridy = 1;
        panelConnection.add(lblPort, gbc_lblPort);
        
        textPort = new JTextField();
        textPort.setColumns(10);
        GridBagConstraints gbc_textPort = new GridBagConstraints();
        gbc_textPort.insets = new Insets(0, 0, 5, 0);
        gbc_textPort.anchor = GridBagConstraints.NORTHWEST;
        gbc_textPort.gridx = 1;
        gbc_textPort.gridy = 1;
        panelConnection.add(textPort, gbc_textPort);
        
        JButton btnConnection = new JButton("Connection");
        btnConnection.addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent arg0) 
            {
                
                JMXServiceURL url = null;
                JMXConnector jmxc = null;
                Set<ObjectName> names = null;
                Set<ObjectName> allNames = null;
                ObjectName query = null;
                
                String host = "localhost";
                String port = "9999";
                
                if(!textHost.getText().isEmpty())
                {
                    host = textHost.getText();
                }
                if(!textPort.getText().isEmpty())
                {
                    port = textPort.getText();
                }
                
                /* Create the connection with mavibot jmx. */
                
                try 
                {
                    url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+host+":"+port+"/jmxrmi");
                    jmxc = JMXConnectorFactory.connect(url, null);
                    mBeanServerConnection = jmxc.getMBeanServerConnection();
                    query = new ObjectName( "org.apache.directory.mavibot.btree:*");
                    names = new TreeSet<ObjectName>(mBeanServerConnection.queryNames(query, null));
                    allNames = new TreeSet<ObjectName>(mBeanServerConnection.queryNames(null, null));
                } 
                catch (Exception e) 
                {
                    JOptionPane.showMessageDialog( MetricPage.this , "Connection error to JMX. Please verify port Number and Address." ); return;
                }
                
                /* Fill the lists of btree names and mbean. */
                
                final String[] tabObjName = new String[names.size()];
                tabRealName = new String[names.size()];
                int sizeToDelete = new String( "org.apache.directory.mavibot.btree:").length();
                
                int i = 0;
                for(ObjectName objName : names)
                {
                    tabRealName[i] = objName.getCanonicalName().substring(sizeToDelete);
                    tabObjName[i] = tabRealName[i].substring(5,tabRealName[i].indexOf(","));
                    ++i;
                }
                
                final String[] tabAllName = new String[allNames.size()];
                i=0;
                for(ObjectName objName : allNames)
                {
                	if(!objName.getCanonicalName().contains("mavibot"))
                	{
	                	tabAllName[i] = objName.getCanonicalName();
	                	++i;
                	}
                }
                
                btreeBeanList.setModel( new AbstractListModel<String>() 
                    {
                        private static final long serialVersionUID = 1L;
                        String[] values = tabObjName;
                        
                        public int getSize() 
                        {
                            return values.length;
                        }
                        
                        public String getElementAt(int index) 
                        {
                            return values[index];
                        }
                    });
                
                statisticList.setModel(new AbstractListModel<String>() 
                    {
                        private static final long serialVersionUID = 1L;
                        String[] values = tabAllName;
                        
                        public int getSize() 
                        {
                            return values.length;
                        }
                        
                        public String getElementAt(int index) 
                        {
                            return values[index];
                        }
                    });
                
                /* Initialize all the jvm mbean. */
                
                try 
                {
                    ObjectName objThread = mBeanServerConnection.queryNames(new ObjectName("java.lang:type=Threading"), null).iterator().next();
                    threadMXBean = JMX.newMBeanProxy(mBeanServerConnection, objThread, com.sun.management.ThreadMXBean.class,false);
                } 
                catch (MalformedObjectNameException e) 
                {
                    e.printStackTrace();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
                
                try 
                {
                    Iterator<ObjectName> objThreads = mBeanServerConnection.queryNames(new ObjectName("java.lang:type=GarbageCollector,name=*"), null).iterator();
                    if(objThreads.hasNext())
                    {
                        gc1MXBean = JMX.newMBeanProxy(mBeanServerConnection, objThreads.next(), com.sun.management.GarbageCollectorMXBean.class,false);
                    }
                    else
                    {
                        gc1MXBean = null;
                    }
                    if(objThreads.hasNext())
                    {
                        gc2MXBean = JMX.newMBeanProxy(mBeanServerConnection, objThreads.next(), com.sun.management.GarbageCollectorMXBean.class,false);
                    }
                    else
                    {
                        gc2MXBean = null;
                    }
                } 
                catch (MalformedObjectNameException e) 
                {
                    e.printStackTrace();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
                
                try 
                {
                    ObjectName objThread = mBeanServerConnection.queryNames(new ObjectName("java.lang:type=OperatingSystem"), null).iterator().next();
                    osMXBean = JMX.newMBeanProxy(mBeanServerConnection, objThread, com.sun.management.OperatingSystemMXBean.class,false);
                } 
                catch (MalformedObjectNameException e) 
                {
                    e.printStackTrace();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }
                
                try 
                {
                    ObjectName objThread = mBeanServerConnection.queryNames(new ObjectName("java.lang:type=Memory"), null).iterator().next();
                    memoryMXBean = JMX.newMXBeanProxy(mBeanServerConnection, objThread, java.lang.management.MemoryMXBean.class,false);
                } catch (MalformedObjectNameException e) 
                {
                    e.printStackTrace();
                } 
                catch (IOException e) 
                {
                    e.printStackTrace();
                }

                refreshStat();
            }
        });
        
        GridBagConstraints gbc_btnConnection = new GridBagConstraints();
        gbc_btnConnection.insets = new Insets(0, 0, 0, 5);
        gbc_btnConnection.gridx = 1;
        gbc_btnConnection.gridy = 2;
        panelConnection.add(btnConnection, gbc_btnConnection);
        
        JPanel panelLists = new JPanel();
        panelLeft.add(panelLists, BorderLayout.CENTER);
        panelLists.setLayout(new GridLayout(3, 1, 0, 0));
        
        JPanel panelBtreeList = new JPanel();
        panelLists.add(panelBtreeList);
        panelBtreeList.setLayout(new GridLayout(1, 1, 0, 0));
        
        btreeBeanList = new JList<String>();
        btreeBeanList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        panelBtreeList.add(new JScrollPane(btreeBeanList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
        btreeBeanList.addMouseListener(new MouseListener() 
        {
            
            @Override
            public void mouseReleased(MouseEvent arg0) 
            {
            }
            
            @Override
            public void mousePressed(MouseEvent arg0) 
            {
            }
            
            @Override
            public void mouseExited(MouseEvent arg0) 
            {
            }
            
            @Override
            public void mouseEntered(MouseEvent arg0) 
            {
            }
            
            @Override
            public void mouseClicked(MouseEvent arg0) 
            {
                if(arg0.getClickCount()==2)
                {
                    try 
                    {
                        ObjectName mbeanName = new ObjectName("org.apache.directory.mavibot.btree:"+tabRealName[btreeBeanList.getSelectedIndex()]);
                        if(tabRealName[btreeBeanList.getSelectedIndex()].contains("JMXMavibotPersistedBtree"))
                        {
                            persistedBtreeMBean = JMX.newMBeanProxy(mBeanServerConnection, mbeanName, JMXMavibotPersistedBtreeMBean.class, false);
                            MetricPage.this.isPersist=true;
                        }
                        else
                        {
                            inMemoryBtreeMBean = JMX.newMBeanProxy(mBeanServerConnection, mbeanName, JMXMavibotInMemoryBtreeMBean.class, false);
                            MetricPage.this.isPersist=false;
                        }
                        refreshStat();
                    } 
                    catch (MalformedObjectNameException e) 
                    {
                        e.printStackTrace();
                    }
                    
                }
                
            }
        });
        
        btreeBeanList.setBorder( new LineBorder( new Color(0, 0, 0), 1, true) );
        
        JPanel panelBeanList = new JPanel();
        panelLists.add(panelBeanList);
        panelBeanList.setLayout(new GridLayout(0, 1, 0, 0));
        
        statisticList = new JList<String>();
        statisticList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        statisticList.setBorder(new LineBorder( new Color(0, 0, 0), 1, true));
        panelBeanList.add(new JScrollPane(statisticList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
        
        
        JPanel panelMethodList = new JPanel();
        panelLists.add(panelMethodList);
        panelMethodList.setLayout(new GridLayout(0, 1, 0, 0));
        
        methodList = new JList<String>();
        methodList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        methodList.setBorder(new LineBorder( new Color(0, 0, 0), 1, true));
        panelMethodList.add(new JScrollPane(methodList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
        
        /* Initialize the statistics panel with the two tables. */
        
        MetricCacheModel mcm = new MetricCacheModel();
        MetricJVMModel mjm = new MetricJVMModel();
        
        this.delai=1000;
        
        JPanel panelRight = new JPanel();
        add(panelRight);
        panelRight.setLayout(new GridLayout(1, 2, 0, 0));
        
        JPanel statisticPanel = new JPanel();
        panelRight.add(statisticPanel);
        statisticPanel.setBorder( new LineBorder( new Color(0, 0, 0), 1, true) );
        statisticPanel.setLayout(new BorderLayout(0, 0));
        
        JPanel panelControl = new JPanel();
        statisticPanel.add(panelControl, BorderLayout.SOUTH);
        GridBagLayout gbl_panelControl = new GridBagLayout();
        gbl_panelControl.columnWeights = new double[]{0.0, 0.0, 0.0};
        gbl_panelControl.rowWeights = new double[]{0.0};
        panelControl.setLayout(gbl_panelControl);
        
        JButton btnRefresh = new JButton("Refresh");
        GridBagConstraints gbc_btnRefresh = new GridBagConstraints();
        gbc_btnRefresh.weightx = 0.3;
        gbc_btnRefresh.anchor = GridBagConstraints.WEST;
        gbc_btnRefresh.insets = new Insets(0, 0, 0, 5);
        gbc_btnRefresh.gridx = 1;
        gbc_btnRefresh.gridy = 0;
        panelControl.add(btnRefresh, gbc_btnRefresh);
        btnRefresh.addActionListener(new ActionListener() 
        {
            public void actionPerformed(ActionEvent arg0) 
            {
                refreshStat();
            }
        });
        
        JPanel panelAutoRefresh = new JPanel();
        GridBagConstraints gbc_panelAutoRefresh = new GridBagConstraints();
        gbc_panelAutoRefresh.weightx = 0.6;
        gbc_panelAutoRefresh.anchor = GridBagConstraints.NORTHWEST;
        gbc_panelAutoRefresh.gridx = 2;
        gbc_panelAutoRefresh.gridy = 0;
        panelControl.add(panelAutoRefresh, gbc_panelAutoRefresh);
        panelAutoRefresh.setLayout(new GridLayout(0, 2, 0, 0));
        
        JLabel lblAutoRefresh = new JLabel("Auto Refresh:");
        panelAutoRefresh.add(lblAutoRefresh);
        
        JCheckBox checkBoxAutoRefresh = new JCheckBox("");
        checkBoxAutoRefresh.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent arg0) 
            {
                if(arg0.getStateChange()==ItemEvent.SELECTED)
                {
                    refreshThread = new RefreshThread(delai);
                    refreshThread.start();
                }
                else
                {
                    refreshThread.endWork();
                }
            }
        });
        panelAutoRefresh.add(checkBoxAutoRefresh);
        
        JLabel lblRefreshDelay = new JLabel("Refresh delay (ms):  ");
        panelAutoRefresh.add(lblRefreshDelay);
        
        textRefreshDelay = new JTextField();
        textRefreshDelay.addKeyListener(new KeyAdapter() 
        {
            @Override
            public void keyPressed(KeyEvent arg0) 
            {
                if(arg0.getKeyCode() == KeyEvent.VK_ENTER)
                {
                    try
                    {
                        delai=Integer.parseInt(textRefreshDelay.getText());
                    }
                    catch(Exception e)
                    {
                        delai=1000;
                    }
                    if(refreshThread.isAlive())
                    {
                        refreshThread.setDelay(delai);
                    }
                }
            }
        });
        panelAutoRefresh.add(textRefreshDelay);
        textRefreshDelay.setColumns(10);
        
        JPanel panelStatisticTables = new JPanel();
        statisticPanel.add(panelStatisticTables, BorderLayout.CENTER);
        panelStatisticTables.setLayout(new GridLayout(2, 1, 0, 0));
        
        tableJVM = new JTable();
        tableJVM.setBorder(new LineBorder(new Color(0, 0, 0)));
        JScrollPane tableJVMScrollPane = new JScrollPane();
        panelStatisticTables.add(tableJVMScrollPane);
        tableJVMScrollPane.setViewportView( tableJVM );
        tableJVM.setModel(mjm);
        tableJVM.setFillsViewportHeight(true);
        tableJVM.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        tableMetric = new JTable();
        tableMetric.setBorder(new LineBorder(new Color(0, 0, 0)));
        JScrollPane tableMetricScrollPane = new JScrollPane();
        panelStatisticTables.add(tableMetricScrollPane);
        tableMetricScrollPane.setViewportView( tableMetric );
        tableMetric.setModel(mcm);
        tableMetric.setFillsViewportHeight(true);
        tableMetric.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        /* Initialize the charts panel. */
        
        JPanel panelChart = new JPanel();
        panelRight.add(panelChart);
        GridBagLayout gbl_panelChart = new GridBagLayout();
        gbl_panelChart.columnWeights = new double[]{0.0};
        gbl_panelChart.rowWeights = new double[]{0.1,0.1,0.3};
        panelChart.setLayout(gbl_panelChart);
        
        cpuPanel = new CourbeJMXPanel(1,"Cpu usage","Time","%",0,100);
        cpuPanel.setSeriesTitle(0, "");
        GridBagConstraints gbc_cpuPanel = new GridBagConstraints();
        gbc_cpuPanel.weightx = 1.0;
        gbc_cpuPanel.weighty = 0.25;
        gbc_cpuPanel.fill = GridBagConstraints.BOTH;
        gbc_cpuPanel.insets = new Insets(5, 5, 5, 5);
        gbc_cpuPanel.gridx = 0;
        gbc_cpuPanel.gridy = 0;
        panelChart.add(cpuPanel, gbc_cpuPanel);
        
        heapMemoryPanel = new CourbeJMXPanel(2,"Heap memory usage","Time","MBs",0,0);
        heapMemoryPanel.setSeriesTitle(0, "Committed memory");
        heapMemoryPanel.setSeriesTitle(1, "Used memory");
        GridBagConstraints gbc_heapMemoryPanel = new GridBagConstraints();
        gbc_heapMemoryPanel.insets = new Insets(0, 5, 0, 5);
        gbc_heapMemoryPanel.weighty = 0.25;
        gbc_heapMemoryPanel.weightx = 1.0;
        gbc_heapMemoryPanel.fill = GridBagConstraints.BOTH;
        gbc_heapMemoryPanel.gridx = 0;
        gbc_heapMemoryPanel.gridy = 1;
        panelChart.add(heapMemoryPanel, gbc_heapMemoryPanel);
        
        nonHeapMemoryPanel = new CourbeJMXPanel(2,"Non heap memory usage","Time","MBs",0,0);
        nonHeapMemoryPanel.setSeriesTitle(0, "Committed memory");
        nonHeapMemoryPanel.setSeriesTitle(1, "Used memory");
        GridBagConstraints gbc_nonHeapMemoryPanel = new GridBagConstraints();
        gbc_nonHeapMemoryPanel.insets = new Insets(5, 5, 0, 5);
        gbc_nonHeapMemoryPanel.weighty = 0.25;
        gbc_nonHeapMemoryPanel.weightx = 1.0;
        gbc_nonHeapMemoryPanel.fill = GridBagConstraints.BOTH;
        gbc_nonHeapMemoryPanel.gridx = 0;
        gbc_nonHeapMemoryPanel.gridy = 2;
        panelChart.add(nonHeapMemoryPanel, gbc_nonHeapMemoryPanel);
        
        hitMissPanel = new CourbeJMXPanel(1,"Cache Hit/Miss","Time","Miss <-> Hit %",0,100);
        hitMissPanel.setSeriesTitle(0, "");
        GridBagConstraints gbc_hitMissPanel = new GridBagConstraints();
        gbc_hitMissPanel.insets = new Insets(5, 5, 5, 5);
        gbc_hitMissPanel.weighty = 0.25;
        gbc_hitMissPanel.weightx = 1.0;
        gbc_hitMissPanel.fill = GridBagConstraints.BOTH;
        gbc_hitMissPanel.gridx = 0;
        gbc_hitMissPanel.gridy = 3;
        panelChart.add(hitMissPanel, gbc_hitMissPanel);
    }
    
    /**
     * 
     * Get the new mbean value and refresh all the tables and charts.
     *
     */
    private void refreshStat()
    {
    	Millisecond time = new Millisecond();
    	
    	/* Update jvm statistics and charts. */
    	
        dataJVM[0][1] = osMXBean.getProcessCpuLoad()*100+"";
        cpuPanel.addValueToSeries(0, time, osMXBean.getProcessCpuLoad()*100);
        
        MemoryUsage mhu= memoryMXBean.getHeapMemoryUsage();
        dataJVM[1][1] = mhu.getCommitted()+"";
        heapMemoryPanel.addValueToSeries(0, time, mhu.getCommitted()/1000000.0);
        dataJVM[2][1] = mhu.getUsed()+"";
        heapMemoryPanel.addValueToSeries(1, time, mhu.getUsed()/1000000.0);
        
        MemoryUsage mnhu= memoryMXBean.getNonHeapMemoryUsage();
        dataJVM[3][1] = mnhu.getCommitted()+"";
        nonHeapMemoryPanel.addValueToSeries(0, time, mnhu.getCommitted()/1000000.0);
        dataJVM[4][1] = mnhu.getUsed()+"";
        nonHeapMemoryPanel.addValueToSeries(1, time, mnhu.getUsed()/1000000.0);

        if(gc1MXBean!=null)
        {
            dataJVM[5][0] = gc1MXBean.getName();
            dataJVM[5][1] = gc1MXBean.getCollectionCount()+"";
        }
        else
        {
            dataJVM[5][0] = "GC";
            dataJVM[5][1] = "Not Available";
        }

        if(gc2MXBean!=null)
        {
            dataJVM[6][0] = gc2MXBean.getName();
            dataJVM[6][1] = gc2MXBean.getCollectionCount()+"";
        }
        else
        {
            dataJVM[6][0] = "GC";
            dataJVM[6][1] = "Not Available";
        }

        dataJVM[7][1] = threadMXBean.getThreadCount()+"";
        
        ((MetricJVMModel)tableJVM.getModel()).fireTableDataChanged();
        
        /* Update btree statistics and chart. */
        
        if(!isPersist && inMemoryBtreeMBean != null)
        {
            dataMetrics[0][1] = inMemoryBtreeMBean.getName();
            dataMetrics[1][1] = inMemoryBtreeMBean.getType();
            dataMetrics[2][1] = inMemoryBtreeMBean.getRevision()+"";
            dataMetrics[3][1] = inMemoryBtreeMBean.getPageSize()+"";
            dataMetrics[4][1] = inMemoryBtreeMBean.getNbElems()+"";
            dataMetrics[5][1] = inMemoryBtreeMBean.getKeySerializerFQCN();
            dataMetrics[6][1] = inMemoryBtreeMBean.getValueSerializerFQCN();
            dataMetrics[7][1] = inMemoryBtreeMBean.getReadTimeOut()+"";
            dataMetrics[8][1] = inMemoryBtreeMBean.getWriteBufferSize()+"";
            dataMetrics[10][1] = "Not Available";
            dataMetrics[11][1] = "Not Available";
            dataMetrics[12][1] = "Not Available";
            dataMetrics[13][1] = "Not Available";
            dataMetrics[14][1] = "Not Available";
            dataMetrics[15][1] = "Not Available";
        }
        else if(persistedBtreeMBean != null)
        {
            dataMetrics[0][1] = persistedBtreeMBean.getName();
            dataMetrics[1][1] = persistedBtreeMBean.getType();
            dataMetrics[2][1] = persistedBtreeMBean.getRevision()+"";
            dataMetrics[3][1] = persistedBtreeMBean.getPageSize()+"";
            dataMetrics[4][1] = persistedBtreeMBean.getNbElems()+"";
            dataMetrics[5][1] = persistedBtreeMBean.getKeySerializerFQCN();
            dataMetrics[6][1] = persistedBtreeMBean.getValueSerializerFQCN();
            dataMetrics[7][1] = persistedBtreeMBean.getReadTimeOut()+"";
            dataMetrics[8][1] = persistedBtreeMBean.getWriteBufferSize()+"";
            dataMetrics[10][1] = persistedBtreeMBean.getCacheSize()+"";
            dataMetrics[11][1] = persistedBtreeMBean.getCacheNbTotalAccess()+"";
            dataMetrics[12][1] = persistedBtreeMBean.getCacheNbPut()+"";
            dataMetrics[13][1] = persistedBtreeMBean.getCacheNbReadAccess()+"";
            dataMetrics[14][1] = persistedBtreeMBean.getCacheNbHits()+"";
            dataMetrics[15][1] = persistedBtreeMBean.getCacheNbMiss()+"";
            double hitMiss = (double)persistedBtreeMBean.getCacheNbMiss()/(double)persistedBtreeMBean.getCacheNbReadAccess()*100;
            hitMissPanel.addValueToSeries(0, time, hitMiss);
        }

        ((MetricCacheModel)tableMetric.getModel()).fireTableDataChanged();
        
    }
    
    /**
     * 
     * Inner class to define the metric btree table model.
     *
     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
     */
    class MetricCacheModel extends DefaultTableModel 
    {
        private static final long serialVersionUID = -6339630786108808273L;
        
        /** Table for column names. */
        private String[] columnNames = new String[] {"Data Type","Value"};

        @Override
        public int getColumnCount() 
        {
            return 2;
        }

        @Override
        public int getRowCount() 
        {
            return dataMetrics.length;
        }

        @Override
        public String getColumnName(int col) 
        {
            return columnNames[col];
        }

        @Override
        public Object getValueAt(int row, int col) 
        {
            return dataMetrics[row][col];
        }

        @Override
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Class getColumnClass(int c)
        {
            return getValueAt(0, c).getClass();
        }

    }
    
    /**
     * 
     * Inner class for the metric jvm table model.
     *
     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
     */
    class MetricJVMModel extends DefaultTableModel 
    {
        private static final long serialVersionUID = -6339630786108808273L;
        
        /** Table for column names. */
        private String[] columnNames = new String[] {"Data Type","Value"};

        @Override
        public int getColumnCount() 
        {
            return 2;
        }

        @Override
        public int getRowCount() 
        {
            return dataJVM.length;
        }

        @Override
        public String getColumnName(int col) 
        {
            return columnNames[col];
        }

        @Override
        public Object getValueAt(int row, int col) 
        {
            return dataJVM[row][col];
        }

        @Override
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Class getColumnClass(int c) 
        {
            return getValueAt(0, c).getClass();
        }

    }
    
    /**
     * 
     * Inner class to define the thread for auto-refresh.
     *
     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
     */
    class RefreshThread extends Thread
    {
        /** The delay of auto-refresh in ms. */
        private int delay;
        
        /** a boolean to stop the thread. */
        private boolean active;
        
        /**
         * 
         * Creates a new instance of RefreshThread.
         *
         * @param delay the delay of auto-refreshing.
         */
        public RefreshThread(int delay)
        {
            this.delay=delai;
            this.active = true;
        }
        

        @Override
        public void run()
        {
            while(active)
            {
                refreshStat();
                try 
                {
                    sleep(delay);
                } 
                catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
            }
        }
        
        /**
         * 
         * Change the delay.
         *
         * @param delay the new delay.
         */
        public void setDelay(int delay)
        {
            this.delay=delay;
        }
        
        /**
         * 
         * Stop the thread.
         *
         */
        public void endWork()
        {
            this.active=false;
        }
    }

}
